package com.atguigu.tingshu.user.service.impl;
import java.util.Date;

import cn.hutool.core.date.DateUtil;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.user.*;
import com.atguigu.tingshu.user.mapper.UserVipServiceMapper;
import com.atguigu.tingshu.user.service.VipServiceConfigService;
import com.atguigu.tingshu.user.startagy.ItemTypeStrategy;
import com.atguigu.tingshu.user.startagy.StrategyFactory;
import com.atguigu.tingshu.vo.user.UserUpdateVo;
import com.google.common.collect.Maps;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.cache.RedisCache;
import com.atguigu.tingshu.common.constant.KafkaConstant;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.service.KafkaService;
import com.atguigu.tingshu.user.mapper.UserInfoMapper;
import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
import com.atguigu.tingshu.user.service.UserInfoService;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.thoughtworks.xstream.converters.time.SystemClockConverter;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

	@Autowired
	private UserInfoMapper userInfoMapper;

	@Autowired
	private WxMaService wxMaService;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private KafkaService kafkaService;

	@Autowired
	private UserPaidAlbumMapper userPaidAlbumMapper;

	@Autowired
	private UserPaidTrackMapper userPaidTrackMapper;

	@Autowired
	private AlbumFeignClient albumFeignClient;

	@Autowired
	private VipServiceConfigService vipServiceConfigService;

	@Autowired
	private UserVipServiceMapper userVipServiceMapper;

	@Autowired
	private StrategyFactory strategyFactory;


	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, String> login(String code) {
		Map<String,String> resultMap = new HashMap<>();
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
			if(sessionInfo != null){
				String openid = sessionInfo.getOpenid();
				UserInfo userInfo = this.lambdaQuery().eq(UserInfo::getWxOpenId, openid).one();
				if(userInfo == null){
					//第一次登录，新增用户
					userInfo = new UserInfo();
					userInfo.setWxOpenId(openid);
					userInfo.setNickname("听友"+ System.currentTimeMillis());
					userInfo.setAvatarUrl("https://tse2-mm.cn.bing.net/th/id/OIP-C.H9x1BxITI75Tc3IMOKJekwAAAA?rs=1&pid=ImgDetMain");
					userInfo.setIsVip(0);
					this.save(userInfo);
					//初始化用户账户
					kafkaService.sendMessage(KafkaConstant.QUEUE_USER_REGISTER,userInfo.getId().toString());
				}
				//生成token
				String token = IdUtil.getSnowflakeNextIdStr();
				//key
				String loginKey = RedisConstant.USER_LOGIN_KEY_PREFIX + token;
				//设置userInfoVo
				UserInfoVo userInfoVo = BeanUtil.toBean(userInfo, UserInfoVo.class);
				//保存到redis
				redisTemplate.opsForValue().set(loginKey,userInfoVo,RedisConstant.USER_LOGIN_KEY_TIMEOUT, TimeUnit.SECONDS);
				//返回给前端
				resultMap.put("token",token);
				return resultMap;
			}
        } catch (WxErrorException e) {
            throw new RuntimeException(e);
        }
        return Map.of();
	}

	@Override
	public UserInfoVo getUserInfo(Long userId) {
		return BeanUtil.toBean(this.getById(userId),UserInfoVo.class);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateUser(Long userId, UserInfoVo userInfoVo) {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(userId);
		userInfo.setNickname(userInfoVo.getNickname());
		userInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
		userInfoMapper.updateById(userInfo);
	}

	@Override
	@RedisCache(prefix = RedisConstant.USER_INFO_PREFIX)
	public UserInfoVo getUserInfoVoById(Long userId) {
		UserInfo userInfo = this.getById(userId);
		UserInfoVo userInfoVo = BeanUtil.toBean(userInfo, UserInfoVo.class);
		return userInfoVo;
	}

	@Override
	public Boolean isPaidAlbum(Long userId, Long albumId) {
		Long l = userPaidAlbumMapper.selectCount(new LambdaQueryWrapper<UserPaidAlbum>()
				.eq(UserPaidAlbum::getUserId, userId)
				.eq(UserPaidAlbum::getAlbumId, albumId));
		return l != null && l > 0;
	}

	@Override
	public List<Long> getUserPaidTrackIdList(Long userId, Long albumId) {
		List<UserPaidTrack> userPaidTracks = userPaidTrackMapper.selectList(new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId).eq(UserPaidTrack::getAlbumId, albumId));
		if(!CollectionUtils.isEmpty(userPaidTracks)){
			return userPaidTracks.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
		}
		return List.of();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void savePaidRecord(Long userId, UserPaidRecordVo userPaidRecordVo) {
		ItemTypeStrategy strategy = strategyFactory.getStrategy(userPaidRecordVo.getItemType());
		strategy.savePaidRecord(userPaidRecordVo);
	}

	/**
	 * 更改用户vip过期
	 */
	@Override
	public void updateVipExpireStatus() {
		List<UserInfo> list = this.list(new LambdaQueryWrapper<UserInfo>()
				.eq(UserInfo::getIsVip, 1)
				.lt(UserInfo::getVipExpireTime, DateUtil.beginOfDay(new Date())));
		if(!CollectionUtils.isEmpty(list)){
			for (UserInfo userInfo : list) {
				userInfo.setIsVip(0);
				userInfo.setUpdateTime(new Date());
			}
			this.updateBatchById(list);
		}
	}
}
